#include "Mainwindow.h"
#include "ui_Mainwindow.h"

#include <QThread>
#include <QProgressDialog>
#include <QApplication>
#include <QTreeView>
#include <QMessageBox>
#include <QInputDialog>

#include <stdexcept>
#include <iostream>

MainWindow::MainWindow(QWidget *parent) try :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    m_Model(new ExtendedFileSystemModel)
{
    ui->setupUi(this);

    m_Model->setRootPath("/");

    if(!connect(ui->treeViewLeft, SIGNAL(dragDropPaths(QString,QString)), this, SLOT(dragDropPaths(QString,QString)))){
        throw std::runtime_error(std::string(Q_FUNC_INFO) + "The SIGNAL(dragDropPaths(QString,QString)) cannot connect to the SLOT(dragDropPaths(QString,QString))\n");
    }

    if(!connect(ui->treeViewRight, SIGNAL(dragDropPaths(QString,QString)), this, SLOT(dragDropPaths(QString,QString)))){
        throw std::runtime_error(std::string(Q_FUNC_INFO) + "The SIGNAL(dragDropPaths(QString,QString)) cannot connect to the SLOT(dragDropPaths(QString,QString))\n");
    }

    QString pwd(QCoreApplication::applicationDirPath());

    //Left tree
    ui->treeViewLeft->setContextMenuPolicy(Qt::CustomContextMenu);
    if(!connect(ui->treeViewLeft, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(contextMenueLeftTreeView(const QPoint &)))){
        throw std::runtime_error(std::string(Q_FUNC_INFO) + "The SIGNAL(customContextMenuRequested(const QPoint &)) cannot connect to the SLOT(contextMenueLeftTreeView(const QPoint &))\n");
    }

    ui->treeViewLeft->setParent(this);
    ui->treeViewLeft->setModel(m_Model.data());
    ui->treeViewLeft->setAnimated(true);
    ui->treeViewLeft->setIndentation(20);
    ui->treeViewLeft->setSortingEnabled(true);
    ui->treeViewLeft->setWindowTitle(pwd);
    ui->treeViewLeft->show();

    //Right tree
    ui->treeViewRight->setContextMenuPolicy(Qt::CustomContextMenu);
    if(!connect(ui->treeViewLeft, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(contextMenueLeftTreeView(const QPoint &)))){
        throw std::runtime_error(std::string(Q_FUNC_INFO) + "The SIGNAL(customContextMenuRequested(const QPoint &)) cannot connect to the SLOT(contextMenueLeftTreeView(const QPoint &))\n");
    }

    ui->treeViewRight->setParent(this);
    ui->treeViewRight->setModel(m_Model.data());
    ui->treeViewRight->setAnimated(true);
    ui->treeViewRight->setIndentation(20);
    ui->treeViewRight->setSortingEnabled(true);
    ui->treeViewRight->setWindowTitle(pwd);
    ui->treeViewRight->show();
}
catch(const std::runtime_error& err){
    std::cerr << err.what();
}

MainWindow::~MainWindow(){}

void MainWindow::copyFile(const QString &filePathFrom, const QString &filePathTo)
{
    QFileInfo pathFrom(filePathFrom);
    QFileInfo pathTo(filePathTo);

    if(!pathFrom.exists()){
        throw std::runtime_error(QString("File \" " + filePathFrom + " \" doesn't exist.").toStdString());
    }

    if(pathTo.isDir()){
        QString strPathTo = pathTo.filePath() + "/" + pathFrom.fileName();
        doCopy(pathFrom.filePath(), strPathTo);
    }
    else if(pathTo.isFile()){
        QString strPathTo = pathTo.canonicalPath() + "/" + pathFrom.fileName();
        doCopy(pathFrom.filePath(), strPathTo);
    }
}

void MainWindow::copyDir(const QString& dirPathFrom, const QString& dirPathTo)
{

    QMessageBox::warning(this, "Warning!", "Cannot copy directory!", QMessageBox::Ok);

    //TODO: implement this function
}

void MainWindow::doCopy(const QString &filePathFrom, const QString& filePathTo)
{
    if(QFile(filePathTo).exists()){
        QMessageBox msg;
        msg.setText("File\" " + filePathTo + " \" has already existed.");
        msg.setInformativeText("Do you want to overwrite it?");
        msg.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
        int ret = msg.exec();
        if(ret == QMessageBox::Yes){
            QProgressDialogPtr progressDialogPtr(new QProgressDialog);
            CopyThread* thread = new CopyThread(filePathFrom, filePathTo, progressDialogPtr, this);

            m_threadPool.start(thread);
        }
    }
    else{
        QProgressDialogPtr progressDialogPtr(new QProgressDialog);
        CopyThread* thread = new CopyThread(filePathFrom, filePathTo, progressDialogPtr, this);

        m_threadPool.start(thread);
    }
}

QString MainWindow::askRename()
{
    QInputDialog inDialog;
    return inDialog.getText(0, "Rename",
                            "New name:", QLineEdit::Normal,
                            "Enter new name", 0);

}

bool MainWindow::askRemove(const QString& str)
{
    QMessageBox msgBox;
    msgBox.setInformativeText("Do you wont to remove item \" " + str + " \" ?");
    msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
    int ret = msgBox.exec();

    if(ret == QMessageBox::Yes){
        return true;
    }

    return false;
}

void MainWindow::doRename(const QString& currentPath)
{
    QString newName = askRename();
    QString newPathName = QFileInfo(currentPath).path() + "/" + newName;
    if(!QFile::rename(currentPath, newPathName)){
        QMessageBox::warning(this, "Warning!", "File \" " + newPathName + " \" cannot be renamed!");
    }
}

void MainWindow::doRemove(const QString& filePath)
{
    if(askRemove(filePath)){
        QFile file(filePath);
        if(!file.remove()){
            QMessageBox::warning(this, "Warning!", "File \" " + filePath + " \" cannot be removed!");
        }
    }
}

void MainWindow::dragDropPaths(const QString& pathFrom , const QString& pathTo)
{
    QFileInfo fileInfoFrom(pathFrom);

    if(fileInfoFrom.isDir()){
        try{
            copyDir(pathFrom, pathTo);
        }
        catch (const std::runtime_error& err){
            QMessageBox::critical(this, "Error!", QString(err.what()), QMessageBox::Ok);
        }
    }
    else if(fileInfoFrom.isFile()){
        try{
            copyFile(pathFrom, pathTo);
        }
        catch (const std::runtime_error& err){
            QMessageBox::critical(this, "Error!", QString(err.what()), QMessageBox::Ok);
        }
    }
}

void MainWindow::showProgressDialog(QProgressDialogPtr progressPtr)
{
    progressPtr->setWindowModality(Qt::WindowModal);
    progressPtr->show();
}

void MainWindow::contextMenueRightTreeView(const QPoint &point)
{
    QMenu *menu=new QMenu(this);

    menu->addAction(QString("Rename"), this, SLOT(onRenameRight()));
    menu->addAction(QString("Remove"), this, SLOT(onRemoveRight()));
    menu->popup(ui->treeViewRight->viewport()->mapToGlobal(point));
}

void MainWindow::contextMenueLeftTreeView(const QPoint &point)
{
    QMenu *menu=new QMenu(this);

    menu->addAction(QString("Rename"), this, SLOT(onRenameLeft()));
    menu->addAction(QString("Remove"), this, SLOT(onRemoveLeft()));
    menu->popup(ui->treeViewLeft->viewport()->mapToGlobal(point));
}

void MainWindow::onRemoveLeft()
{
    QString filePath = TreeView::getItemPath(ui->treeViewLeft);
    doRemove(filePath);
}

void MainWindow::onRenameLeft()
{
    QString filePath = TreeView::getItemPath(ui->treeViewLeft);
    doRename(filePath);
}

void MainWindow::onRemoveRight()
{
    QString filePath = TreeView::getItemPath(ui->treeViewRight);
    doRemove(filePath);
}

void MainWindow::onRenameRight()
{
    QString filePath = TreeView::getItemPath(ui->treeViewRight);
    doRename(filePath);
}

